#include <cmn/utils.h>
#include "pdb/public_include.h"
#include "pdb/policy_table.h"
#include "pdb/policy_parse.h"

//extern struct _policy_table *g_pt;

//in main.c, init policy table
int
policy_init()
{
	key_t key_policy_table;
//	int shmid_policy_table = 0;
	int len = 0;

	g_pt = NULL;

	len = sizeof(struct _policy_table)+sizeof(struct _policy_element)*POLICY_TABLE_LEN;

	key_policy_table = ftok( IPC_MEM_FILE, 'a' );
	shmid_policy_table = shmget( key_policy_table, len, IPC_CREAT|0604 );
	if( shmid_policy_table == -1 )
	{	
		DEBUG( ERROR, "[%s][%d]err=[%s]\n", __FILE__, __LINE__, strerror(errno) );
		return -1;
	}

	g_pt = (struct _policy_table *) shmat( shmid_policy_table, 0, 0 );
	if( g_pt == NULL )
	{
		DEBUG( ERROR, "[%s][%d]err=[%s]\n", __FILE__, __LINE__, strerror(errno) );
		return -1;
	}

	memset( g_pt, 0x00, len );

	init_policy_table( g_pt );

	DEBUG( ERROR, "[%s][%d]\n", __FILE__, __LINE__ );

	return 0;
}

int
add_policy( struct _policy_table *policy_table, struct _policy_element *p_elem )
{
	int lower = 0;
	int up = 0;

	if( p_elem == NULL || policy_table == NULL )
	{
		DEBUG( ERROR, "input param is null" );
		return -1;
	}

	//DEBUG( INFO, "operation=[%d],up=[%u],lower=[%u],value0=[%lld],value1=[%lld]", p_elem->operation, p_elem->up_limit, p_elem->lower_limit, p_elem->value[0], p_elem->value[1] );

	insert_policy_table( policy_table, p_elem );

	//DEBUG( ERROR, "[%s][%d]used_len=[%d]\n", __FILE__, __LINE__, policy_table->used_len );

	return 0;
}

//init policy table
int
init_policy_table( struct _policy_table *p )
{
	if( p == NULL )
	{
		DEBUG( ERROR, "[%s][%d]policy NULL error\n", __FILE__, __LINE__ );
		return -1;
	}

	p->policy_table_flag = POLICY_TABLE_USED;	
	p->policy_table_len = POLICY_TABLE_LEN;	
	p->used_len = 0;
	p->current_used_policy = 0;

	DEBUG( ERROR, "[%s][%d]init_policy_table function \n", __FILE__, __LINE__ );

	return 0;
}

int
is_policy_init( struct _policy_table *p )
{
	int ret = -1;

	if( p == NULL )
	{
		DEBUG( ERROR, "[%s][%d]policy NULL error\n", __FILE__, __LINE__ );
		return -1;
	}

	if( (p->policy_table_flag&POLICY_TABLE_USED) == POLICY_TABLE_USED )
	{
		ret = 0;
	}

	return ret;
}
//add timer policy
int
insert_policy_table( struct _policy_table *policy, struct _policy_element *elem )
{
	if( policy == NULL )
	{
		DEBUG( ERROR, "[%s][%d]policy NULL error\n", __FILE__, __LINE__ );
		return -1;
	}

	if( is_policy_init(policy) != 0 )
	{	
		DEBUG( ERROR, "[%s][%d]policy does not init\n", __FILE__, __LINE__ );
		return -1;
	}

	if( policy->used_len >= policy->policy_table_len )
	{
		DEBUG( ERROR, "[%s][%d]policy's num is greater than default POLICY NUM\n", __FILE__, __LINE__ );
		return -1;
	}

	struct _policy_element *p_elem = NULL;
	p_elem= &(policy->p_element[policy->used_len]);
	if( p_elem == NULL )
	{
		DEBUG( ERROR, "[%s][%d]p_elem is NULL error\n", __FILE__, __LINE__ );
		return -1;
	}

	p_elem->operation = elem->operation;
	p_elem->up_limit = elem->up_limit;
	p_elem->lower_limit = elem->lower_limit;
	p_elem->value[0] = elem->value[0];
	p_elem->value[1] = elem->value[1];

/*
	DEBUG( INFO, "[%s][%d]operation=[%d]\n", __FILE__, __LINE__, p_elem->operation );
	DEBUG( INFO, "[%s][%d]up=[%u]\n", __FILE__, __LINE__, p_elem->up_limit );
	DEBUG( INFO, "[%s][%d]lower=[%u]\n", __FILE__, __LINE__, p_elem->lower_limit );
	DEBUG( INFO, "[%s][%d]value=[%lld]\n", __FILE__, __LINE__, p_elem->value[0] );
	DEBUG( INFO, "[%s][%d]value=[%lld]\n", __FILE__, __LINE__, p_elem->value[1] );
*/

	//insert_policy_hash_table( hash_table, p_elem, lower_limit, up_limit );

	//num ++
	policy->used_len++;
	//DEBUG( INFO, "[%s][%d]used_len=[%d]\n", __FILE__, __LINE__, policy->used_len );

	return 0;
}

//init policy hash table
int
init_policy_hash_table( struct _policy_hash_table *hash_p )
{
	if( hash_p == NULL )
	{
		DEBUG( ERROR, "[%s][%d]policy NULL error\n", __FILE__, __LINE__ );
		return -1;
	}
	hash_p->hash_table_flag = HASH_TABLE_USED;	
	hash_p->hash_table_len = POLICY_HASH_TABLE_LEN;	
	return 0;
}

//print
int
print_policy_table( struct _policy_table *p )
{
	int i = 0;

	if( NULL == p )
	{
		DEBUG( ERROR, "[%s][%d]input error\n", __FILE__, __LINE__ );
		return -1;
	}

	DEBUG( INFO, "[%s][%d]policy_table_flag=[%d], policy_table_len=[%d]\n", __FILE__, __LINE__, p->policy_table_flag, p->policy_table_len );
	DEBUG( INFO, "[%s][%d]used_len=[%d]\n", __FILE__, __LINE__, p->used_len );

	for( i=0; i<p->used_len; i++ )
	{
		DEBUG( INFO, "[%s][%d]lower=[%u], up=[%u]\n", __FILE__, __LINE__, (p->p_element[i]).lower_limit, (p->p_element[i]).up_limit );
		DEBUG( INFO, "[%s][%d]value1=[%lld], value2=[%lld]\n", __FILE__, __LINE__, (p->p_element[i]).value[0], (p->p_element[i]).value[1] );
	}
}

//struct policy_elment 
//*
int
find_policy_table( struct _policy_table *p, int key )
{
	int i = 0;

	if( NULL == p )
	{
		DEBUG( ERROR, "[%s][%d]input error\n", __FILE__, __LINE__ );
		return -1;
	}

	if( is_policy_init(p) != 0 )
	{	
		DEBUG( ERROR, "[%s][%d]policy does not init\n", __FILE__, __LINE__ );
		return -1;
	}

	for( i=0; i<p->used_len; i++ )
	{
		//printf( "lower=[%u], up=[%u]\n", (p->p_element[i]).lower_limit, (p->p_element[i]).up_limit );
		if( key >= (p->p_element[i]).lower_limit && key < (p->p_element[i]).up_limit )
		{
			DEBUG( INFO, "value1=[%lld], value2=[%lld]\n", (p->p_element[i]).value[0], (p->p_element[i]).value[1] );
			return i;//add by macro
		}
	}

	return 0;
}

/*
int
get_policy_table_current_version( struct _policy_table *p )
{
	int i = 0;

	if( NULL == p )
	{
		DEBUG( ERROR, "[%s][%d]input error\n", __FILE__, __LINE__ );
		return -1;
	}

	if( is_policy_init(p) != 0 )
	{	
		DEBUG( ERROR, "[%s][%d]policy does not init\n", __FILE__, __LINE__ );
		return -1;
	}


	return p->version;
}
*/

int
delete_policy_table( struct _policy_table * p )
{
	if( is_policy_init(p) != 0 )
	{	
		DEBUG( ERROR, "[%s][%d]policy does not init\n", __FILE__, __LINE__ );
		return -1;
	}

//free
}

int
hash_table_used( struct _policy_hash_table *p )
{
	if( NULL == p )
	{
		DEBUG( ERROR, "[%s][%d]input param is NULL error\n", __FILE__, __LINE__ );
		return -1;
	}

	return p->hash_table_flag;
}

//insert hash table
//insert one element to hash table
int
insert_policy_hash_table( struct _policy_hash_table *policy_hash_table, struct _policy_element *p, unsigned long  lower, unsigned long up )
{
	unsigned long i = 0;
	if( policy_hash_table == NULL || p == NULL )
	{
		DEBUG( ERROR, "[%s][%d]hash_table is NULL error\n", __FILE__, __LINE__ );
		return -1;
	}

	if( ( hash_table_used( policy_hash_table ) & HASH_TABLE_USED )!= HASH_TABLE_USED )
	{
		DEBUG( ERROR, "[%s][%d]input error\n", __FILE__, __LINE__ );
		return -1;
	}	

	if( lower < 0 || up > policy_hash_table->hash_table_len )
	{
		DEBUG( ERROR, "[%s][%d]error\n", __FILE__, __LINE__ );
		return -1;
	}

	if( lower > up )
	{
		i = lower;
		lower = up;
		up = i;
	}

	for( i=lower; i<up; i++ )
	{
		(policy_hash_table->hash_table)[i] = p;
	}

	return 0;
}


int
delete_policy_hash_table()
{
//free
}


struct policy_elment 
*find_hash_table( struct _policy_hash_table *p, int key )
{
	if( NULL == p )
	{
		DEBUG( ERROR, "[%s][%d]input error\n", __FILE__, __LINE__ );
		return NULL;
	}

	if( ( hash_table_used( p )&HASH_TABLE_USED )!= HASH_TABLE_USED )
	{
		DEBUG( ERROR, "[%s][%d]input error\n", __FILE__, __LINE__ );
		return NULL;
	}	

	if( key < 0 || key >= p->hash_table_len )
	{
		DEBUG( ERROR, "[%s][%d]invalid key\n", __FILE__, __LINE__ );
		return NULL;
	}

	return p->hash_table[key];
}

/*
int	
main()
{
	key_t key_policy_table;
	int len = 0;
	int shmid_policy_table = 0;

	len = sizeof(struct _policy_table)+sizeof(struct _policy_element)*POLICY_TABLE_LEN;

	struct _policy_table *pt = NULL;

	key_policy_table = ftok( "/usr/local/var/run", 'a' );
	shmid_policy_table = shmget( key_policy_table, len, IPC_CREAT|0604 );
	if( shmid_policy_table == -1 )
	{	
		DEBUG( ERROR, "[%s][%d]err=[%s]\n", __FILE__, __LINE__, strerror(errno) );
		return -1;
	}

	pt = (struct _policy_table *) shmat( shmid_policy_table, 0, 0 );
	if( pt == NULL )
	{
		DEBUG( ERROR, "[%s][%d]err=[%s]\n", __FILE__, __LINE__, strerror(errno) );
		return -1;
	}

	//pt = (struct _policy_table *)malloc(len);
	
	memset( pt, 0x00, len );

	init_policy_table( pt );

	insert_policy_table( pt, 1, 0, 2, 10, 8000000, 32000000 );
//	insert_policy_table( pt, 1, 0, 10, 20, 7000000, 28000000 );
//	insert_policy_table( pt, 1, 0, 20, 90, 5000000, 25000000 );
//	insert_policy_table( pt, 1, 0, 90, 100, 1000000, 4000000 );

	sleep( 10000 );
//print_policy_table( pt );
//	find_policy_table( pt, 19 );
//	find_policy_table( pt, 20 );
//	find_policy_table( pt, 95 );
}
*/
